import * as XLSX from 'xlsx'
import { message } from 'ant-design-vue'

/**
 * 读取 Excel 文件中的指定 sheet 页数据并返回数据数组。
 * @param {File} file - 用户上传的 Excel 文件。
 * @param sheetNo - 需要读取的 sheet 页序号，默认为 0。
 * @returns {Promise<Array>} - 返回一个包含数据的二维数组。
 */

export const readExcelSheet = (file, sheetNo = 0) => {
  return new Promise((resolve, reject) => {
    // 启动一个不关闭的加载中提示
    message.loading('正在读取文件...')
    const reader = new FileReader()

    reader.onload = e => {
      try {
        const data = new Uint8Array(e.target.result)
        const workbook = XLSX.read(data, { type: 'array', cellDates: true, cellNF: false, cellText: true, dateNF: 'yyyy-mm-dd' })

        // Select the specified sheet or default to the first one
        const selectedSheetName = workbook.SheetNames[sheetNo]
        const worksheet = workbook.Sheets[selectedSheetName]

        // Get all rows as raw data
        const xlsxData = XLSX.utils.sheet_to_json(worksheet, { header: 1, raw: false, dateNF: 'yyyy-mm-dd' })

        // If the length of a row's data does not match the maximum length, pad it with null
        const maxLength = Math.max(...xlsxData.map(row => row.length))
        const xlsxResData = xlsxData
          .map(row => {
            // 如果行的长度小于最大长度，并且至少有一个元素不为null或者空，则填充
            if (row.length > 0) {
              row.push(...Array(maxLength - row.length).fill(null))
            }
            return row
          })
          .filter(row => row.length > 0)

        console.log('xlsxResData:', xlsxResData)

        setTimeout(() => {
          message.success('文件读取成功')

          resolve(xlsxResData) // Return the processed JSON data
        }, 400)
      } catch (error) {
        reject(error) // Handle any errors that occur during processing
        message.error('文件读取失败')
      }
    }

    reader.onerror = error => reject(error) // Handle file read errors
    reader.readAsArrayBuffer(file)
  })
}

/**
 * 读取 Excel 文件中的所有 sheet 页名称。
 * @param {File} file - 用户上传的 Excel 文件。
 * @returns {Promise<Array>} - 返回一个包含所有 sheet 页名称的数组。
 */
export function getExcelSheetNames(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()

    reader.onload = e => {
      const data = new Uint8Array(e.target.result)
      const workbook = XLSX.read(data, { type: 'array' })

      // 获取所有的 sheet 页名称
      const sheetNames = workbook.SheetNames
      resolve(sheetNames)
    }

    reader.onerror = error => {
      reject(error)
    }

    reader.readAsArrayBuffer(file)
  })
}

/**
 * 自动识别 Excel 文件中的表头行号，并返回读取的数据。
 * @param {File} file - 用户上传的 Excel 文件。
 * @param {string} sheetName - 需要读取的 sheet 页名称。
 * @returns {Promise<{ headerRow: number, data: Array }>} - 返回一个包含表头行号和数据的对象。
 */
export function detectHeaderRowAndReadSheet(file, sheetName) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()

    reader.onload = e => {
      const d = new Uint8Array(e.target.result)
      const workbook = XLSX.read(d, { type: 'array' })

      const sheet = workbook.Sheets[sheetName]
      if (!sheet) {
        reject(new Error('Sheet not found'))
        return
      }

      // 将 sheet 转换为二维数组
      const sheetData = XLSX.utils.sheet_to_json(sheet, { header: 1 })

      // 自动识别表头行号
      const headerRow = detectHeaderRow(sheetData)

      // 使用识别的表头行号重新读取数据
      const data = XLSX.utils.sheet_to_json(sheet, { header: 'A', range: headerRow })

      resolve({ headerRow, data })
    }

    reader.onerror = error => {
      reject(error)
    }

    reader.readAsArrayBuffer(file)
  })
}

/**
 * 检测表头的行号
 * @param {Array} sheetData - Excel 表数据的二维数组格式。
 * @returns {number} - 识别出的表头行号（从 0 开始）。
 */
function detectHeaderRow(sheetData) {
  // 遍历每一行数据，检查是否可能是表头
  for (let i = 0; i < sheetData.length; i++) {
    const row = sheetData[i]

    // 判断是否有足够的非空单元格，表头一般非空
    const nonEmptyCells = row.filter(cell => cell !== null && cell !== undefined && cell !== '')
    if (nonEmptyCells.length < row.length / 2) {
      continue // 如果非空单元格不足一半，可能不是表头
    }

    // 判断是否大部分是字符串（不是数值或日期等）
    const stringCells = row.filter(cell => typeof cell === 'string')
    if (stringCells.length < nonEmptyCells.length * 0.8) {
      continue // 如果字符串比例不高，可能不是表头
    }

    // 判断是否有重复的单元格
    const uniqueCells = [...new Set(nonEmptyCells)]
    if (uniqueCells.length !== nonEmptyCells.length) {
      continue // 如果有重复的单元格，可能不是表头
    }

    // 如果通过所有检测条件，认为这一行是表头
    return i
  }

  // 如果没有检测到符合条件的表头行，默认返回第一行作为表头
  return 0
}

/**
 * 读取 Excel 文件并返回表头和数据。
 * @returns {Promise<{ file }>} - 返回一个包含表头和数据的对象。
 */

export const openFileDialogAndReadExcel = () => {
  return new Promise((resolve, reject) => {
    const fileInput = document.createElement('input')
    fileInput.type = 'file'
    fileInput.accept = '.xls,.xlsx,.csv'
    fileInput.style.display = 'none'

    fileInput.addEventListener('change', async event => {
      //读取文件中
      try {
        message.loading('正在读取文件...')
        const file = await event.target['files'][0]
        message.success('文件读取成功')
        resolve({ file })
      } catch (error) {
        reject(error)
      } finally {
        document.body.removeChild(fileInput)
        message.destroy()
      }
    })

    // Clear the value to ensure the change event is triggered even if the same file is selected
    fileInput.value = ''
    document.body.appendChild(fileInput)
    fileInput.click()
  })
}

/**
 * 检查字符串中汉字的数量
 * @param {string} str - 要检查的字符串
 * @returns {number} - 汉字的数量
 */
function countChineseCharacters(str) {
  return (str.match(/[\u4e00-\u9fa5]/g) || []).length
}

/**
 * 替换公式中的单元格引用为对应的表头汉字，并用 # 包含
 * @param {Array} nonEmptyHeaders - 包含表头信息及其公式的数组
 * @returns {Array} - 替换后的数组
 */
function replaceFormulasWithHeaders(nonEmptyHeaders) {
  const headersMap = nonEmptyHeaders.reduce((map, item) => {
    map[item.columnLetter] = item.header
    return map
  }, {})

  return nonEmptyHeaders.map(item => {
    if (item.formula) {
      item.formula = item.formula.replace(/([A-Z]+)(\d*)(:([A-Z]+)(\d*))?/g, (match, col1, row1, range, col2, row2) => {
        if (range) {
          // 处理范围引用
          const startCol = XLSX.utils.decode_col(col1)
          const endCol = XLSX.utils.decode_col(col2)
          let headers = []
          for (let col = startCol; col <= endCol; col++) {
            const header = headersMap[XLSX.utils.encode_col(col)]
            if (header) {
              headers.push(`#${header}#`)
            }
          }
          return headers.join(',')
        } else {
          // 处理单个单元格引用
          const header = headersMap[col1]
          return header ? `#${header}#` : match
        }
      })
      item.formulaHtml = item.formula.replace(/#(.*?)#/g, '<span class="filed-span">#$1#</span>')
    }
    return item
  })
}

/**
 * 检查并处理公式，如果包含 XLOOKUP 或 VLOOKUP  ROW() 函数，则将公式设置为 null。
 * @param {string} formula - 需要检查的公式字符串。
 * @returns {string|null} - 处理后的公式，如果包含指定函数则返回 null，否则返回原公式。
 */
function sanitizeFormula(formula) {
  const containsXLOOKUP = /XLOOKUP\(/i.test(formula)
  const containsVLOOKUP = /VLOOKUP\(/i.test(formula)
  const containsROW = /ROW\(/i.test(formula)

  if (containsXLOOKUP || containsVLOOKUP || containsROW) {
    return null
  }

  return formula
}

/**
 * 获取表头信息及其公式
 * @param {File} file - Excel 文件对象
 * @param {number} sheetNo - sheet 页码（从 0 开始）
 * @param {boolean} flag - 是否拼接合并单元格的表头
 * @returns {Promise<Array>} - 包含表头信息及其公式的数组
 */
export const getSheetHeadersWithFormulas = async ({ file, sheetNo, flag = false }) => {
  const reader = new FileReader()
  reader.readAsArrayBuffer(file)

  return await new Promise((resolve, reject) => {
    reader.onload = e => {
      const data = new Uint8Array(e.target.result)
      const workbook = XLSX.read(data, { type: 'array' })
      const sheetName = workbook.SheetNames[sheetNo]
      const sheet = workbook.Sheets[sheetName]

      const range = XLSX.utils.decode_range(sheet['!ref'])
      let headerRow = -1
      let maxChineseCount = 0

      // 识别汉字最多的行作为表头
      for (let row = range.s.r; row <= range.e.r; row++) {
        let chineseCount = 0

        for (let col = range.s.c; col <= range.e.c; col++) {
          const cellAddress = XLSX.utils.encode_cell({ r: row, c: col })
          const cell = sheet[cellAddress]
          if (cell && cell.v) {
            chineseCount += countChineseCharacters(cell.v.toString())
          }
        }

        if (chineseCount > maxChineseCount) {
          maxChineseCount = chineseCount
          headerRow = row
        }
      }

      const headersWithFormulas = []
      const headersMap = {}

      // 处理表头和合并单元格
      if (headerRow >= 0) {
        const previousRow = headerRow - 1

        // 初始化表头
        for (let col = range.s.c; col <= range.e.c; col++) {
          const headerCellAddress = XLSX.utils.encode_cell({ r: headerRow, c: col })
          const headerCell = sheet[headerCellAddress]
          const headerValue = headerCell ? headerCell.v.toString().trim().replace(/\s+/g, '') : ''
          if (headerValue) {
            headersMap[XLSX.utils.encode_col(col)] = headerValue
          }
        }

        // 处理公式
        for (let col = range.s.c; col <= range.e.c; col++) {
          const headerCellAddress = XLSX.utils.encode_cell({ r: headerRow, c: col })
          const headerCell = sheet[headerCellAddress]
          const formulaCellAddress = XLSX.utils.encode_cell({ r: headerRow + 1, c: col })
          const formulaCell = sheet[formulaCellAddress]

          const headerValue = headerCell ? headerCell.v.toString().trim().replace(/\s+/g, '') : ''
          if (headerValue) {
            headersWithFormulas[col] = {
              header: headerValue,
              formula: formulaCell ? sanitizeFormula(formulaCell.f) : null,
              columnLetter: XLSX.utils.encode_col(col),
              index: col
            }
          }
        }

        // 检查合并单元格并拼接值 或者在同一行不是合并单元格但是有值的情况下拼接值
        if (flag) {
          // 处理合并单元格
          if (sheet['!merges']) {
            sheet['!merges'].forEach(merge => {
              if (merge.s.r === previousRow) {
                const mergedValue = sheet[XLSX.utils.encode_cell({ r: previousRow, c: merge.s.c })].v.toString().trim().replace(/\s+/g, '')

                for (let col = merge.s.c; col <= merge.e.c; col++) {
                  if (headersWithFormulas[col]) {
                    headersWithFormulas[col].header = `${mergedValue}${headersWithFormulas[col].header ? headersWithFormulas[col].header : ''}`.trim()
                    // 标记是否需要拼接
                    headersWithFormulas[col].whetherOrNotToSplic = true
                  }
                }
              }
            })
          }

          // 处理同一行不是合并单元格但是有值的情况
          for (let col = range.s.c; col <= range.e.c; col++) {
            console.log(range, 'col', col)
            const cellAddress = XLSX.utils.encode_cell({ r: previousRow, c: col })
            const cell = sheet[cellAddress]
            if (cell && cell.v) {
              const value = cell.v.toString().trim().replace(/\s+/g, '')
              //如果表头上一行是单项值，不是合并单元格，但是有值，并且没有拼接过，则拼接
              if (value && headersWithFormulas[col] && !headersWithFormulas[col].whetherOrNotToSplic) {
                headersWithFormulas[col].header = `${value}${headersWithFormulas[col].header ? headersWithFormulas[col].header : ''}`.trim()
              }
            }
          }
        }

        // 确保每个表头都有合并的值，如果表头仍然为空则使用合并的值
        for (let col = range.s.c; col <= range.e.c; col++) {
          if (!headersWithFormulas[col]) {
            const mergedHeaderCell = sheet[XLSX.utils.encode_cell({ r: previousRow, c: col })]
            if (mergedHeaderCell) {
              const mergedValue = mergedHeaderCell.v.toString().trim().replace(/\s+/g, '')
              console.log('mergedValue', mergedValue)
              if (mergedValue) {
                headersWithFormulas[col] = {
                  header: mergedValue,
                  formula: null,
                  columnLetter: XLSX.utils.encode_col(col),
                  index: col
                }
              }
            }
          }
        }
      }

      // 过滤掉 header 为空的项
      const nonEmptyHeaders = headersWithFormulas.filter(item => item && item.header)

      // 替换公式中的单元格引用为对应的表头汉字，并用 # 包含
      const result = replaceFormulasWithHeaders(nonEmptyHeaders)
      console.log('result', result)

      resolve(result) // 返回非空表头
    }

    reader.onerror = error => {
      reject(error)
    }
  })
}
